import MD5 from 'crypto-js/md5'

/**
 * Uc工具类
 * 
 * 获取编码器（UcEncoder）、请求客户端类（暂未实现）等
 */
export default class UcUtils
{
    static getUcEncoder(ucKey){
        return new UcEncoder(ucKey);
    }
}

/**
 * 加密器
 * 
 * 对数据进行加密、解密操作
 */
class UcEncoder
{
    constructor(ucKey){
        this.ucKey = ucKey;
        this.keyCLength = 4;
    }

    /**
     * @private
     * @param {int} start 
     * @param {int} count 
     * @returns {number[]}
     */
    getRange(start, count){
        let range = [];
        for (let i = start; i < count + start; i++) {
            range.push(i)
        }
        return range
    }

    encode(rawText, expiry = 0){
        let key = MD5(this.ucKey).toString();
        let timestamp = (new Date()).getTime(),
            microtimeStr = (timestamp % 1000 / 1000 ).toFixed(8) + ' ' + parseInt(timestamp / 1000); // 拼接成形如“0.12856600 1581594293”的字符串
        let keyA = MD5(key.slice(0, 16)).toString(),
            keyB = MD5(key.slice(16, 32)).toString(),
            keyC = MD5(microtimeStr).toString().slice(-this.keyCLength),
            keyCrypto = keyA + MD5(keyA + keyC).toString(); // key特征信息 + 当前时间特征信息
        let expiryStr = (expiry?expiry + parseInt((new Date()).getTime()) : 0).toString().padStart(10, 0),
            encodedText = expiryStr + MD5(rawText + keyB).toString().slice(0, 16) + rawText; // 有效期信息 + 正文特征信息 + 正文
        let result = '', box = this.getRange(0, 256), rndKey = [];
        for (let i = 0; i < 256; i++) {
            rndKey.push(keyCrypto.charCodeAt(i % keyCrypto.length)); // 获取keyCrypto中的每个字符的ASCII码，并加入数组
        }
        for (let j = 0, i = 0; i < 256; i++) {
            j = (j + box[i] + rndKey[i]) % 256;
            let tmp = box[i];box[i] = box[j];box[j] = tmp; // 交换i、j的值    
        }
        for (let i = 0, j = 0, a = 0; i < encodedText.length; i++) {
            a = (a + 1) % 256;
            j = (j + box[a]) % 256;
            let tmp = box[a]; box[a] = box[j]; box[j] = tmp;
            result += String.fromCharCode(encodedText.charCodeAt(i) ^ box[(box[a] + box[j]) % 256])
        }
        return keyC + window.btoa(result).replace('=', '')
    }

    decode(rawText){
        let key = MD5(this.ucKey).toString();
        let timestamp = (new Date()).getTime();
        let keyA = MD5(key.slice(0, 16)).toString(),
            keyB = MD5(key.slice(16, 32)).toString(),
            keyC = rawText.slice(0, this.keyCLength),
            keyCrypto = keyA + MD5(keyA + keyC).toString(); // key特征信息 + 当前时间特征信息
        let encodedText = window.atob(rawText.slice(this.keyCLength)); 
        let result = '', box = this.getRange(0, 256), rndKey = [];
        for (let i = 0; i < 256; i++) {
            rndKey.push(keyCrypto.charCodeAt(i % keyCrypto.length)); // 获取keyCrypto中的每个字符的ASCII码，并加入数组
        }
        for (let j = 0, i = 0; i < 256; i++) {
            j = (j + box[i] + rndKey[i]) % 256;
            let tmp = box[i];box[i] = box[j];box[j] = tmp; // 交换i、j的值    
        }
        for (let i = 0, j = 0, a = 0; i < encodedText.length; i++) {
            a = (a + 1) % 256;
            j = (j + box[a]) % 256;
            let tmp = box[a]; box[a] = box[j]; box[j] = tmp;
            result += String.fromCharCode(encodedText.charCodeAt(i) ^ box[(box[a] + box[j]) % 256])
        }
        if((result.slice(0,10) == 0 || result.slice(0,10) - timestamp > 0) && result.slice(10, 26) == MD5(result.slice(26) + keyB).toString().slice(0, 16)) {
            return result.slice(26);
		} else {
			return '';
		}
    }
}

/**
 * UC请求客户端类
 * 
 * 将操作的Request实例发送到uc_server中,然后获得对应的Response类
 * 
 * // 大致操作流程
 * let req = new RegRequest, client = new UcClient;
 * req.p1 = v1 // 设置参数
 * let resp = client.request(req) 
 */
class UcClient
{
    // todo
}

/**
 * 操作请求基类
 */
class UcRequest
{
    // todo
}

/**
 * 操作响应基类
 */
class UcResponse
{
    // tod
}

/**
 * 注册请求
 */
class RegRequest extends UcRequest
{
    // todo
}

/**
 * 注册操作的响应结果类
 */
class RegResponse extends UcResponse
{
    // todo
}

/**
 * 登入请求
 */
class LoginRequest extends UcRequest
{
    // todo
}

/**
 * 登录操作的响应结果类
 */
class LoginResponse extends UcResponse
{
    // todo
}

/**
 * 登出请求
 */
class LogoutRequest extends UcRequest
{
    // todo
}

/**
 * 登出操作的响应结果类
 */
class LogoutResponse extends UcResponse
{
    // todo
}